package com.scott.framework.context;

import com.scott.framework.annotation.Autowired;
import com.scott.framework.annotation.Controller;
import com.scott.framework.annotation.Service;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class SimpleApplicationContext {

    private static final String SCAN_PACKAGE = "scan-package";

    /**
     * 所有被扫描的包
     */
    private List<String> classCache = new ArrayList<String>();

    private Map<String, Object> instanceMapping = new ConcurrentHashMap<String, Object>();


    public SimpleApplicationContext(String location) {
        System.out.println(">>>>>>>>>   ioc container init start  <<<<<<<<<<");
        //加载properties配置文件
        try {
            //spring IOC容器 执行过程
            //定位
            InputStream is = this.getClass().getClassLoader().getResourceAsStream(location);

            //载入
            Properties config = new Properties();
            config.load(is);

            //注册 spring 的处理流程是根据配置文件获取所有类的定义，beanDefinition，此处可以不需要处理,
            // 此处只处理根据配置文件找出所有的 class文件
            doRegister(config.getProperty(SCAN_PACKAGE));

            //初始化
            doCreateBean();

            //注入
            populate();

        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println(">>>>>>>>>   ioc container init success  <<<<<<<<<<");

    }

    /**
     * 根据配置的扫描包路径扫描出所有的是Controller的class文件
     */
    private void doRegister(String packageName) {
        URL classUrl = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));

        File dir = new File(classUrl.getFile());

        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                doRegister(packageName + "." + file.getName());
            } else {
                classCache.add(packageName + "." + file.getName().replace(".class", ""));
            }
        }
    }


    /**
     * 容器初始化
     */
    private void doCreateBean() {

        //没有注册信息 直接返回
        if (classCache.size() == 0) {
            System.out.println(">>>>>>>>>   没有扫描到类  <<<<<<<<<<");
            return;
        }
        try {
            for (String className : classCache) {

                //Spring 源码中此处是要进行对应的类类型判断，进而选择是用jdk代理，还是用cglib代理
                Class<?> clazz = Class.forName(className);

                if (clazz.isAnnotationPresent(Controller.class)) {
                    //将类名首字母小写作为key
                    instanceMapping.put(clazz.getName(), clazz.newInstance());
                } else if (clazz.isAnnotationPresent(Service.class)) {
                    //如果Service用设置了name 则优先使用自定义的名称,否则用默认规则，

                    Service service = clazz.getAnnotation(Service.class);

                    //如果注解上设置了名称，则将此名称作为Bean的key
                    if (!"".equals(service.value())) {
                        instanceMapping.put(service.value(), clazz.newInstance());
                        continue;
                    }

                    //如果没有设置名称，则需要考虑一下特殊的情况
                    Class<?>[] interfaces = clazz.getInterfaces();
                    for (Class<?> i : interfaces) {
                        instanceMapping.put(i.getName(), clazz.newInstance());
                    }

                }
            }
        } catch (Exception e) {
            System.out.println(">>>>>>>>>   异常" + Arrays.toString(e.getStackTrace()) + "  <<<<<<<<<<");
        }
    }

    /**
     * 依赖注入
     */
    private void populate() {
        //判断容器中是否有类，如果没有，就不需要依赖注入
        if (instanceMapping.isEmpty()) {
            return;
        }
        for (Map.Entry<String, Object> entry : instanceMapping.entrySet()) {
            //通过java反射来进行依赖注入
            //获取对应的所有属性值
            Field[] fields = entry.getValue().getClass().getDeclaredFields();

            //循环所有属性值，找到注解了LcsAutowired注解，进行依赖注入
            for (Field field : fields) {
                //如果没有LcsAutowired，则不需要进行依赖注入
                if (!field.isAnnotationPresent(Autowired.class)) {
                    continue;
                }

                Autowired autowired = field.getAnnotation(Autowired.class);

                //获取注入的key值
                String beanName = autowired.value().trim();

                //如果key为空，则使用默认的类型来进行注入
                if ("".equals(beanName)) {
                    beanName = field.getType().getName();
                }
                //将此属性设置为可访问的，兼容private修饰的属性
                field.setAccessible(true);

                try {
                    field.set(entry.getValue(), instanceMapping.get(beanName));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }


            }

        }
    }

    /**
     * 字符串首字母小写
     *
     * @param str 输入
     * @return 输出
     */
    private String lowerFirstChar(String str) {
        char[] chars = str.toCharArray();
        //通过ascii 码值增加
        chars[0] += 32;
        return String.valueOf(chars);
    }

    public Object getBean(String name) {
        return null;
    }

    public Map<String, Object> getAll() {
        return instanceMapping;
    }
}
